---
title: "Analyse des Diamants : Les Facteurs du Prix đź’Ž"
subtitle: "Projet d'Analyse Descriptive Approfondie"
author: "Abir Hamda"
date: today
date-format: "DD MMMM YYYY"
format:
html:
theme: cosmo
toc: true
toc-title: "đź“‹ Sommaire"
toc-depth: 3
number-sections: true
code-fold: show
code-tools: true
smooth-scroll: true
embed-resources: true
css: styles.css
editor: visual
execute:
warning: false
message: false
echo: true
---
```{r setup, include=FALSE}
# Configuration globale
knitr::opts_chunk$set(
echo = TRUE,
warning = FALSE,
message = FALSE,
fig.align = 'center',
fig.width = 10,
fig.height = 6,
dpi = 300
)
# Charger les packages
library(ggplot2)
library(dplyr)
library(corrplot)
library(scales)
library(knitr)
library(gridExtra)
# Charger les données
data(diamonds)
# Désactiver notation scientifique
options(scipen = 999)
# Thème ggplot par défaut
theme_set(theme_minimal(base_size = 14))
# Échantillon pour performance (certains graphiques)
set.seed(123)
diamonds_sample <- diamonds %>% sample_n(10000)
```
::: {.hero-banner style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 60px 20px; text-align: center; border-radius: 15px; margin-bottom: 40px; box-shadow: 0 10px 30px rgba(0,0,0,0.2);"}
## đź’Ž Les 4C des Diamants
**Carat • Cut • Color • Clarity**
### `r format(nrow(diamonds), big.mark=" ")` diamants analysés
*Comprendre les facteurs qui déterminent le prix pour optimiser les décisions business*
:::
------------------------------------------------------------------------
# Introduction {#introduction}
## Contexte du Projet
Ce rapport présente une **analyse descriptive approfondie** du dataset `diamonds`, qui contient les caractéristiques et prix de **53 940 diamants**.
### Question de Recherche Principale
> **"Quels sont les facteurs qui influencent le prix d'un diamant, et comment peut-on optimiser notre stratégie de pricing et d'inventaire ?"**
## Objectifs de l'Analyse
::: {.callout-note icon="false"}
### 🎯 Objectifs Spécifiques
1. **Identifier** les variables ayant le plus d'impact sur le prix
2. **Analyser** les relations entre les caractéristiques des diamants
3. **Découvrir** des patterns et insights non-intuitifs
4. **Formuler** des recommandations stratégiques basées sur les données
:::
## Méthodologie
- **Outil** : R 4.x + RStudio
- **Packages** : `ggplot2`, `dplyr`, `corrplot`, `scales`
- **Dataset** : `diamonds` (package ggplot2)
- **Approche** : Analyse descriptive univariée, bivariée et multivariée
------------------------------------------------------------------------
# Exploration des Données {#exploration}
## Structure du Dataset
```{r apercu}
# Afficher la structure avec glimpse
glimpse(diamonds)
```
::: callout-tip
### 📊 Informations Clés
- **53 940 observations** (diamants)
- **10 variables** : 7 numériques + 3 catégorielles ordonnées
- **Aucune valeur manquante** (dataset propre)
:::
## Variables du Dataset
```{r table-variables, echo=FALSE}
# Tableau descriptif des variables
variables_info <- data.frame(
Variable = c("carat", "cut", "color", "clarity", "depth", "table", "price", "x", "y", "z"),
Type = c("Numérique", "Catégorielle", "Catégorielle", "Catégorielle",
"Numérique", "Numérique", "Numérique", "Numérique", "Numérique", "Numérique"),
Description = c(
"Poids du diamant (0.2-5.01 carats)",
"Qualité de la taille (Fair < Good < Very Good < Premium < Ideal)",
"Couleur (D=meilleur → J=pire)",
"Pureté (I1=pire → IF=parfait)",
"Profondeur totale en % (43-79%)",
"Largeur de la table en % (43-95%)",
"Prix en USD ($326 - $18,823)",
"Longueur en mm (0-10.74)",
"Largeur en mm (0-58.9)",
"Profondeur en mm (0-31.8)"
)
)
kable(variables_info, caption = "Description des Variables du Dataset")
```
## Statistiques Descriptives Globales
```{r stats-base}
# Statistiques du prix
summary(diamonds$price)
```
::: {.callout-important icon="false"}
### 💰 Statistiques Clés du Prix
| Mesure | Valeur |
|------------------|--------------------------------------------|
| **Prix Minimum** | `r dollar(min(diamonds$price))` |
| **Prix Moyen** | `r dollar(mean(diamonds$price))` |
| **Prix Médian** | `r dollar(median(diamonds$price))` |
| **Prix Maximum** | `r dollar(max(diamonds$price))` |
| **Écart-Type** | `r dollar(round(sd(diamonds$price), 2))` |
| **Q1 (25%)** | `r dollar(quantile(diamonds$price, 0.25))` |
| **Q3 (75%)** | `r dollar(quantile(diamonds$price, 0.75))` |
**Observation** : Le prix médian (`r dollar(median(diamonds$price))`) est inférieur au prix moyen (`r dollar(round(mean(diamonds$price)))`), ce qui indique une **distribution asymétrique à droite** (présence de diamants très chers).
:::
## Statistiques par Qualité de Coupe
```{r table-summary}
# Tableau récapitulatif par Cut
diamonds_summary <- diamonds %>%
group_by(cut) %>%
summarise(
Nombre = format(n(), big.mark=" "),
Pourcentage = paste0(round(100 * n() / nrow(diamonds), 1), "%"),
`Prix Moyen` = dollar(round(mean(price))),
`Prix Médian` = dollar(median(price)),
`Carat Moyen` = round(mean(carat), 2)
) %>%
arrange(desc(`Prix Moyen`))
kable(diamonds_summary, caption = "Statistiques Détaillées par Qualité de Coupe")
```
::: callout-warning
### ⚠️ Paradoxe Observé
Les diamants "Fair" (qualité inférieure) ont un **prix moyen plus élevé** que les "Ideal" !
**Explication** : Ce paradoxe s'explique par un **carat moyen supérieur** dans la catégorie Fair (`r round(mean(diamonds$carat[diamonds$cut == "Fair"]), 2)` vs `r round(mean(diamonds$carat[diamonds$cut == "Ideal"]), 2)` pour Ideal). Le poids (carat) domine tellement le prix qu'il masque l'effet de la qualité de coupe.
:::
------------------------------------------------------------------------
# Analyse Univariée {#univarie}
## Distribution du Prix
```{r dist-prix}
# Histogramme + densité du prix
ggplot(diamonds, aes(x = price)) +
geom_histogram(aes(y = after_stat(density)), bins = 80,
fill = "#667eea", color = "white", alpha = 0.7) +
geom_density(color = "#764ba2", linewidth = 1.5) +
geom_vline(xintercept = mean(diamonds$price),
linetype = "dashed", color = "red", linewidth = 1) +
annotate("text", x = mean(diamonds$price) + 3000, y = 0.00015,
label = paste("Moyenne =", dollar(round(mean(diamonds$price)))),
color = "red", size = 5) +
scale_x_continuous(labels = dollar_format()) +
labs(
title = "Distribution du Prix des Diamants",
subtitle = paste0("n = ", format(nrow(diamonds), big.mark=" "), " diamants | Distribution asymétrique à droite"),
x = "Prix (USD)",
y = "Densité"
)
```
**Interprétations** :
- Distribution **fortement asymétrique à droite** (skewed right)
- Concentration importante de diamants Ă **bas prix** (\<5000 USD)
- Présence de **valeurs extrêmes** (outliers) au-delà de 15 000 USD
- La moyenne est tirée vers le haut par les diamants très chers
## Distribution du Carat
```{r dist-carat}
# Histogramme du carat avec seuils psychologiques
ggplot(diamonds, aes(x = carat)) +
geom_histogram(bins = 100, fill = "#ff9800", color = "white", alpha = 0.8) +
geom_vline(xintercept = c(0.5, 1.0, 1.5, 2.0),
linetype = "dashed", color = "#e74c3c", linewidth = 1.2) +
annotate("text", x = c(0.5, 1.0, 1.5, 2.0), y = 8500,
label = c("0.5ct", "1.0ct", "1.5ct", "2.0ct"),
color = "#e74c3c", size = 5, fontface = "bold") +
labs(
title = "Distribution du Poids des Diamants",
subtitle = "Pics observés aux seuils psychologiques (0.5, 1.0, 1.5, 2.0 carats)",
x = "Carat (poids)",
y = "Nombre de Diamants"
)
```
::: callout-tip
### đź’ˇ Insight : Seuils Psychologiques
Les **pics à 0.5, 1.0, 1.5 et 2.0 carats** révèlent des **seuils psychologiques** de demande.
**Opportunité Business** : Proposer des diamants de 0.95 carat au lieu de 1.0 carat permet une **économie de 10-15%** pour le client sans différence visible, tout en maintenant des marges attractives.
:::
## Répartition des Variables Catégorielles
```{r categories-barplots, fig.height=10}
# Cut
p1 <- ggplot(diamonds, aes(x = cut, fill = cut)) +
geom_bar(alpha = 0.8) +
scale_fill_brewer(palette = "Set2") +
labs(title = "Répartition par Cut", x = NULL, y = "Nombre") +
theme(legend.position = "none") +
geom_text(stat = 'count', aes(label = after_stat(count)), vjust = -0.5, size = 4)
# Color
p2 <- ggplot(diamonds, aes(x = color, fill = color)) +
geom_bar(alpha = 0.8) +
scale_fill_brewer(palette = "Spectral") +
labs(title = "Répartition par Color", x = NULL, y = "Nombre") +
theme(legend.position = "none") +
geom_text(stat = 'count', aes(label = after_stat(count)), vjust = -0.5, size = 4)
# Clarity
p3 <- ggplot(diamonds, aes(x = clarity, fill = clarity)) +
geom_bar(alpha = 0.8) +
scale_fill_brewer(palette = "Accent") +
labs(title = "Répartition par Clarity", x = NULL, y = "Nombre") +
theme(legend.position = "none", axis.text.x = element_text(angle = 45, hjust = 1)) +
geom_text(stat = 'count', aes(label = after_stat(count)), vjust = -0.5, size = 4)
# Combiner
grid.arrange(p1, p2, p3, ncol = 2)
```
**Observations** :
- **Cut** : "Ideal" domine avec `r round(100 * mean(diamonds$cut == "Ideal"), 1)`% des diamants
- **Color** : Répartition relativement équilibrée, pic à "G" (`r round(100 * mean(diamonds$color == "G"), 1)`%)
- **Clarity** : "SI1" est le plus fréquent (`r round(100 * mean(diamonds$clarity == "SI1"), 1)`%)
------------------------------------------------------------------------
# Analyse Bivariée {#bivarie}
## Le Carat : Facteur Dominant du Prix
Le carat (poids) est la variable ayant l'impact le plus significatif sur le prix.
### Relation Prix vs Carat
```{r prix-carat}
# Scatterplot avec courbe de tendance
ggplot(diamonds_sample, aes(x = carat, y = price)) +
geom_point(alpha = 0.3, color = "#667eea", size = 1.5) +
geom_smooth(method = "loess", color = "#764ba2", linewidth = 2, se = TRUE, fill = "#764ba2", alpha = 0.2) +
scale_y_continuous(labels = dollar_format()) +
labs(
title = "Relation Prix vs Carat : Corrélation Très Forte",
subtitle = paste("Corrélation de Pearson =", round(cor(diamonds$price, diamonds$carat), 3),
"| Relation non-linéaire (exponentielle)"),
x = "Carat (poids)",
y = "Prix (USD)"
) +
theme_minimal(base_size = 13)
```
::: callout-important
### 🔥 Insight Majeur : Corrélation 0.92
La corrélation entre Prix et Carat est de **`r round(cor(diamonds$price, diamonds$carat), 3)`**, ce qui indique une **relation très forte et positive**.
**Points Clés** : - La relation est **non-linéaire** : le prix augmente de manière **exponentielle** avec le carat - Un diamant de 2 carats ne coûte PAS 2× le prix d'un 1 carat, mais plutôt **4-5× plus cher** - Plus le diamant est lourd, plus la **variabilité du prix** augmente (effet des autres facteurs)
:::
## Influence de la Qualité de Coupe (Cut)
```{r boxplot-cut}
ggplot(diamonds, aes(x = reorder(cut, price, FUN = median), y = price, fill = cut)) +
geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
scale_fill_brewer(palette = "Set2") +
scale_y_continuous(labels = dollar_format()) +
coord_flip() +
labs(
title = "Distribution du Prix par Qualité de Coupe",
subtitle = "Ordonné par prix médian croissant",
x = "Qualité de Coupe",
y = "Prix (USD)"
) +
theme(legend.position = "none")
```
**Interprétations** :
- Contrairement à l'intuition, "Ideal" n'a **pas le prix médian le plus élevé**
- Explication : Les "Ideal" ont en moyenne un **carat plus faible**
- Pour comparer équitablement, il faut **contrôler pour le carat** (voir section multivariée)
## Influence de la Couleur (Color)
```{r boxplot-color}
ggplot(diamonds, aes(x = color, y = price, fill = color)) +
geom_violin(alpha = 0.7) +
geom_boxplot(width = 0.2, fill = "white", alpha = 0.5, outlier.alpha = 0.3) +
scale_fill_brewer(palette = "Spectral", direction = -1) +
scale_y_continuous(labels = dollar_format()) +
labs(
title = "Distribution du Prix par Couleur",
subtitle = "D = Incolore (meilleur) • J = Jaune pâle (moins bon)",
x = "Couleur",
y = "Prix (USD)"
) +
theme(legend.position = "none")
```
**Observations** :
- Les couleurs **D, E, F** (incolores) tendent vers des prix plus élevés
- Paradoxe similaire au Cut : effet du carat moyen différent par catégorie
- **Recommandation** : Color G-H offre un excellent rapport qualité/prix (15-20% moins cher que D-E, différence invisible)
## Influence de la Pureté (Clarity)
```{r boxplot-clarity}
ggplot(diamonds, aes(x = clarity, y = price, fill = clarity)) +
geom_violin(alpha = 0.7) +
geom_boxplot(width = 0.2, fill = "white", alpha = 0.5, outlier.alpha = 0.3) +
scale_fill_brewer(palette = "Purples") +
scale_y_continuous(labels = dollar_format()) +
labs(
title = "Distribution du Prix par Pureté",
subtitle = "IF = Internally Flawless (parfait) • I1 = Included (imparfait)",
x = "Pureté (Clarity)",
y = "Prix (USD)"
) +
theme(legend.position = "none", axis.text.x = element_text(angle = 45, hjust = 1))
```
**Insights** :
- Tendance générale : meilleure pureté = prix plus élevé
- **Sweet spot** : VS2 (Very Slightly Included 2) → invisible à l'œil nu, 30-40% moins cher que IF
- Les catégories SI1-SI2 représentent **`r round(100 * mean(diamonds$clarity %in% c("SI1", "SI2")), 1)`%** du marché
------------------------------------------------------------------------
# Analyse Multivariée {#multivarie}
## Matrice de Corrélation
```{r correlation, fig.height=8}
# Calculer corrélations pour variables numériques
cor_vars <- diamonds %>%
select(carat, depth, table, price, x, y, z) %>%
cor()
# Visualiser avec corrplot
corrplot(cor_vars,
method = "color",
type = "upper",
tl.col = "black",
tl.cex = 1.2,
tl.srt = 45,
addCoef.col = "black",
number.cex = 1,
col = colorRampPalette(c("#6D9EC1", "white", "#E46726"))(200),
title = "Matrice de Corrélation - Variables Numériques",
mar = c(0, 0, 2, 0))
```
::: callout-note
### 🔍 Analyse des Corrélations
**Corrélations Fortes avec le Prix** :
- **Carat** : `r round(cor(diamonds$carat, diamonds$price), 3)` 🔥 (facteur dominant)
- **x (longueur)** : `r round(cor(diamonds$x, diamonds$price), 3)`
- **y (largeur)** : `r round(cor(diamonds$y, diamonds$price), 3)`
- **z (profondeur)** : `r round(cor(diamonds$z, diamonds$price), 3)`
**Corrélations Faibles avec le Prix** :
- **depth** : `r round(cor(diamonds$depth, diamonds$price), 3)` (impact négligeable)
- **table** : `r round(cor(diamonds$table, diamonds$price), 3)` (impact négligeable)
**Observation Clé** : Les dimensions x, y, z sont **fortement corrélées au carat** (logique : plus le diamant est lourd, plus il est grand). Elles n'apportent donc pas d'information supplémentaire par rapport au carat.
:::
## Prix vs Carat par Qualité de Coupe
```{r prix-carat-cut, fig.height=8}
# Facet wrap par Cut
ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
geom_point(alpha = 0.2, size = 0.8) +
geom_smooth(method = "loess", se = FALSE, linewidth = 1.5) +
facet_wrap(~cut, ncol = 3) +
scale_color_brewer(palette = "Set1") +
scale_y_continuous(labels = dollar_format()) +
labs(
title = "Prix vs Carat par Qualité de Coupe",
subtitle = "Chaque qualité suit une courbe exponentielle similaire",
x = "Carat (poids)",
y = "Prix (USD)"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
```
**Interprétations** :
- Toutes les qualités de coupe suivent une **courbe exponentielle similaire**
- À carat égal, "Ideal" tend à être légèrement plus cher que "Fair"
- L'effet du Cut est **modéré comparé au Carat**
## Heatmap : Prix Moyen par Cut et Color
```{r heatmap-cut-color}
# Créer données agrégées
heatmap_data <- diamonds %>%
group_by(cut, color) %>%
summarise(prix_moyen = mean(price), n = n(), .groups = "drop")
# Heatmap
ggplot(heatmap_data, aes(x = color, y = cut, fill = prix_moyen)) +
geom_tile(color = "white", linewidth = 0.5) +
geom_text(aes(label = dollar(round(prix_moyen))), color = "white", size = 3.5, fontface = "bold") +
scale_fill_gradient2(low = "#3498db", mid = "#f39c12", high = "#e74c3c",
midpoint = 4000, labels = dollar_format()) +
labs(
title = "Prix Moyen par Combinaison Cut-Color",
subtitle = "Zones rouges = prix élevés | Zones bleues = prix bas",
x = "Couleur (D=meilleur → J=pire)",
y = "Qualité de Coupe",
fill = "Prix Moyen"
) +
theme_minimal(base_size = 13) +
theme(axis.text.x = element_text(angle = 0))
```
**Insights** :
- Les combinaisons **Fair + J/I** ont des prix moyens élevés (effet du carat moyen)
- **Ideal + D** n'est pas la plus chère (carat moyen plus faible)
- Pour une analyse juste, il faudrait **contrĂ´ler pour le carat**
------------------------------------------------------------------------
# Insights Avancés {#insights}
## Top 10 Diamants les Plus Chers
```{r top-expensive}
top_diamants <- diamonds %>%
arrange(desc(price)) %>%
select(carat, cut, color, clarity, price, x, y, z) %>%
head(10) %>%
mutate(
Rang = 1:10,
Prix = dollar(price),
Dimensions = paste0(x, "Ă—", y, "Ă—", z, " mm")
) %>%
select(Rang, carat, cut, color, clarity, Prix, Dimensions)
kable(top_diamants, caption = "Les 10 Diamants les Plus Chers du Dataset")
```
**Observations** :
- Tous ont un **carat \> 2.0**
- Qualité de coupe : majoritairement **Premium et Ideal**
- Couleurs variées (pas uniquement D-E)
- Le prix maximum atteint **\$18,823**
## Segmentation par Tranche de Prix
```{r segments-prix}
# Créer segments
diamonds_segments <- diamonds %>%
mutate(segment = case_when(
price < 1000 ~ "Économique (<1K)",
price < 5000 ~ "Milieu de gamme (1K-5K)",
price < 10000 ~ "Premium (5K-10K)",
TRUE ~ "Luxe (>10K)"
)) %>%
mutate(segment = factor(segment, levels = c("Économique (<1K)",
"Milieu de gamme (1K-5K)",
"Premium (5K-10K)",
"Luxe (>10K)")))
# Statistiques par segment
stats_segments <- diamonds_segments %>%
group_by(segment) %>%
summarise(
Nombre = format(n(), big.mark=" "),
Pourcentage = paste0(round(100 * n() / nrow(diamonds), 1), "%"),
`Prix Moyen` = dollar(round(mean(price))),
`Carat Moyen` = round(mean(carat), 2),
.groups = "drop"
)
kable(stats_segments, caption = "Répartition des Diamants par Segment de Prix")
```
```{r plot-segments}
# Visualiser segments
ggplot(diamonds_segments, aes(x = segment, fill = segment)) +
geom_bar(alpha = 0.8) +
scale_fill_brewer(palette = "Spectral") +
labs(
title = "Nombre de Diamants par Segment de Prix",
x = NULL,
y = "Nombre de Diamants"
) +
theme_minimal(base_size = 13) +
theme(legend.position = "none", axis.text.x = element_text(angle = 30, hjust = 1)) +
geom_text(stat = 'count', aes(label = format(after_stat(count), big.mark=" ")),
vjust = -0.5, size = 5, fontface = "bold")
```
::: callout-tip
### đź’Ľ Implications Business
- **`r round(100 * mean(diamonds$price < 1000), 1)`%** des diamants sont dans la gamme Économique
- **`r round(100 * mean(diamonds$price >= 1000 & diamonds$price < 5000), 1)`%** dans le Milieu de gamme (segment le plus large)
- **`r round(100 * mean(diamonds$price >= 10000), 1)`%** dans le Luxe (marges élevées)
**Recommandation** : Prioriser le stock dans le segment Milieu de gamme (1K-5K) qui représente la majorité de la demande.
:::
## Top 10 Combinaisons Cut + Color
```{r top-combinations}
top_combo <- diamonds %>%
group_by(cut, color) %>%
summarise(
`Prix Moyen` = dollar(round(mean(price))),
`Carat Moyen` = round(mean(carat), 2),
Nombre = format(n(), big.mark=" "),
.groups = 'drop'
) %>%
arrange(desc(`Carat Moyen`)) %>%
head(10)
kable(top_combo, caption = "Top 10 Combinaisons Cut-Color par Prix Moyen (contrôlé par Carat)")
```
**Observation** : Les combinaisons avec les prix moyens les plus élevés sont celles avec le **carat moyen le plus élevé**, confirmant la dominance du poids.
## Analyse des Valeurs ExtrĂŞmes
```{r outliers-analysis}
# Identifier les outliers (prix > Q3 + 1.5*IQR)
Q1 <- quantile(diamonds$price, 0.25)
Q3 <- quantile(diamonds$price, 0.75)
IQR_price <- Q3 - Q1
seuil_outlier <- Q3 + 1.5 * IQR_price
n_outliers <- sum(diamonds$price > seuil_outlier)
pct_outliers <- round(100 * n_outliers / nrow(diamonds), 2)
# Stats des outliers
outliers_stats <- diamonds %>%
filter(price > seuil_outlier) %>%
summarise(
Nombre = n(),
`Prix Moyen` = dollar(round(mean(price))),
`Carat Moyen` = round(mean(carat), 2),
`Prix Max` = dollar(max(price))
)
```
**Résultats** :
- **`r format(n_outliers, big.mark=" ")`** diamants sont considérés comme outliers (`r pct_outliers`%)
- Seuil d'outlier : **`r dollar(round(seuil_outlier))`**
- Ces diamants ont un carat moyen de **`r round(mean(diamonds$carat[diamonds$price > seuil_outlier]), 2)`** (vs `r round(mean(diamonds$carat), 2)` globalement)
------------------------------------------------------------------------
# Conclusions & Recommandations {#conclusions}
## Synthèse des Insights Clés
::: {.callout-important icon="false"}
### 🎯 5 Insights Majeurs
1. **Le Carat est ROI** : Corrélation de **`r round(cor(diamonds$price, diamonds$carat), 3)`** avec le prix (facteur dominant)
2. **Relation Non-Linéaire** : Le prix augmente de manière **exponentielle** avec le carat (un diamant de 2ct coûte 4-5× plus qu'un 1ct)
3. **Seuils Psychologiques** : Pics de demande Ă \*\*0.5, 1.0, 1.5, 2
:::